Skip to content

feat(homelab): self-host Plane issue tracker - #2007

Open
shepherdjerred wants to merge 1 commit into
mainfrom
self-host-plane
Open

feat(homelab): self-host Plane issue tracker#2007
shepherdjerred wants to merge 1 commit into
mainfrom
self-host-plane

Conversation

@shepherdjerred

Copy link
Copy Markdown
Owner

No description provided.

@shepherdjerred

Copy link
Copy Markdown
Owner Author

This change is part of the following stack:

Change managed by git-spice.

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 8, 2026

Copy link
Copy Markdown

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

Qodo Logo

## Summary

Deploy Plane Commercial as a private, issue-tracking-only service through the official `plane-enterprise` Helm chart.

## Changes

- Pin chart `3.1.0` and app `v3.0.1`, with generated Helm types.
- Add the local Plane infrastructure chart and layered ArgoCD applications.
- Configure native authentication, local Postgres/Redis/RabbitMQ on `zfs-ssd`, and disable vendor ingress, MinIO, OpenSearch, PI, and runner services.
- Route Plane through a private Tailscale Ingress at `plane.tailnet-1a49.ts.net`.
- Store attachments in the SeaweedFS `plane-attachments` bucket through the storage proxy.
- Add the dedicated 1Password-backed `plane-secrets` item and explicit Velero PVC policy entries.
- Add synthesis tests and durable deployment plan documentation.

## Verification

- Full cdk8s tests: 330 passed, 14 expected skips.
- Helm compatibility render passed, including Plane.
- Typecheck, lint, Prettier, gitleaks, 1Password validation, and OpenTofu validation passed.
- Vendor manifest inspection confirmed the four Plane stateful claim templates, `plane-secrets` references, no vendor Ingress, and no PI/runner resources.

## Deployment follow-up

Live ArgoCD sync/health, Tailscale HTTPS access, native login, issue workflows, attachment persistence, tailnet-only access, and Velero discovery still need operator verification after the change is published to the GitOps branch.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 8, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Self-host Plane Commercial in homelab with private Tailscale ingress

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add Argo CD apps to deploy Plane Commercial from the official Helm repo.
• Create a local Plane “infrastructure” chart for 1Password secrets and Tailscale-only ingress.
• Provision attachment storage and backup coverage for Plane stateful volumes.
Diagram

graph TD
  Argo["Argo CD"] --> Vendor["Helm repo: helm.plane.so"] --> PlaneApp["Plane app (plane-enterprise)"] --> NS["Namespace: plane"] --> S3[("SeaweedFS S3 bucket")]
  Argo --> CM["Chartmuseum"] --> InfraChart["Plane infra chart"] --> NS
  OneP{{"1Password operator"}} --> Secret["Secret: plane-secrets"] --> PlaneApp
  TS["Tailscale ingress"] --> Ing["Ingress: plane-ingress"] --> PlaneApp
  NS --> Velero["Velero backups"]
  subgraph Legend
    direction LR
    _svc["K8s/App"] ~~~ _db[("Storage")]
    _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use external/shared DB + broker services
  • ➕ Avoids non-PSA-restricted bundled images in the vendor chart
  • ➕ Centralizes backups/monitoring for Postgres/Redis/RabbitMQ
  • ➕ Easier resource tuning and HA later
  • ➖ More up-front wiring (connection URLs, credentials, networking)
  • ➖ Potentially diverges from vendor chart defaults/documentation
2. Deploy Plane Community Edition instead of Commercial
  • ➕ No commercial licensing/prime server dependency
  • ➕ Smaller feature surface to harden
  • ➖ May lose Commercial-only features/UX expected for issue tracking
  • ➖ Migration path may be non-trivial if features diverge
3. Replace 1PasswordItem with ExternalSecrets/SealedSecrets
  • ➕ More standard GitOps patterns and portability across clusters
  • ➕ Can integrate with multiple secret backends
  • ➖ Loses tight coupling to existing 1Password workflow
  • ➖ Adds another operator/tooling surface if not already present

Recommendation: Current approach (vendor chart + local infra chart + Tailscale-only ingress + 1Password-backed secret) is a good fit for a private homelab deployment and keeps credentials out of Git. The main follow-up to consider is migrating off the vendor chart’s bundled Postgres/Redis/RabbitMQ if Pod Security restrictions or HA/operability become priorities.

Files changed (15) +4095 / -5

Tests (2) +189 / -4
pvc-backup-policy.test.tsUpdate backup policy counts for newly included Plane PVCs +4/-4

Update backup policy counts for newly included Plane PVCs

• Adjusts expected totals to account for four new backup-enabled PVC entries. Continues asserting no duplicate PVC keys and stable include/exclude counts.

packages/homelab/src/cdk8s/src/backup-policy/pvc-backup-policy.test.ts

plane.test.tsAdd synthesis tests for Plane Argo apps and private routing +185/-0

Add synthesis tests for Plane Argo apps and private routing

• Adds tests that assert the Plane Argo CD Application pins chart/app versions and disables vendor ingress. Also verifies the infra chart renders the OnePasswordItem secret bridge and the expected Tailscale ingress path map.

packages/homelab/src/cdk8s/src/resources/argo-applications/plane.test.ts

Documentation (1) +53 / -0
2026-08-07_plane-commercial-issue-tracker.mdDocument the Plane Commercial self-hosting plan +53/-0

Document the Plane Commercial self-hosting plan

• Adds an in-progress plan describing how Plane Commercial will be deployed via Helm/Argo CD with Tailscale-only ingress. Captures key configuration choices (disabled vendor ingress/AI/runner/minio/opensearch, SeaweedFS attachments, Velero inventory) and remaining validation steps.

packages/docs/plans/2026-08-07_plane-commercial-issue-tracker.md

Other (12) +3853 / -1
index.tsExport Plane enterprise Helm value types +1/-0

Export Plane enterprise Helm value types

• Extends the generated Helm type barrel to include the Plane enterprise chart types. Enables typed values usage in CDK8s/Argo application definitions.

packages/homelab/src/cdk8s/generated/helm/index.ts

plane-enterprise.types.tsAdd generated TypeScript types for plane-enterprise Helm chart +3487/-0

Add generated TypeScript types for plane-enterprise Helm chart

• Introduces a large generated type definition file for the upstream Plane enterprise Helm chart. Provides strongly typed Helm values/parameters used by the homelab CDK8s code when constructing Argo CD Applications.

packages/homelab/src/cdk8s/generated/helm/plane-enterprise.types.ts

Chart.yamlCreate local Helm chart metadata for Plane infrastructure +6/-0

Create local Helm chart metadata for Plane infrastructure

• Adds a new local chart definition used to publish infrastructure resources that complement the vendor Plane chart (private ingress + secret bridge). Uses templated version/appVersion placeholders for chart packaging.

packages/homelab/src/cdk8s/helm/plane/Chart.yaml

onepassword-vault-snapshot.jsonRefresh 1Password vault snapshot with Plane secrets item +53/-1

Refresh 1Password vault snapshot with Plane secrets item

• Updates the snapshot timestamp and records a new vault item corresponding to Plane Commercial secrets. Supports validation that Kubernetes secret references match the vault contents without committing credentials.

packages/homelab/src/cdk8s/onepassword-vault-snapshot.json

pvc-backup-policy.jsonAdd Plane PVCs to explicit Velero backup inventory +24/-0

Add Plane PVCs to explicit Velero backup inventory

• Registers Plane’s stateful PVCs (monitor, Postgres, RabbitMQ, Redis) as backup-enabled entries. Documents the rationale for each to ensure Velero discovery/coverage.

packages/homelab/src/cdk8s/src/backup-policy/pvc-backup-policy.json

apps.tsWire Plane Argo applications into the apps chart +6/-0

Wire Plane Argo applications into the apps chart

• Imports Plane application constructors and registers both the infrastructure app and the vendor chart app in the main apps chart. Ensures Argo CD will reconcile Plane alongside other homelab workloads.

packages/homelab/src/cdk8s/src/cdk8s-charts/apps.ts

plane.tsAdd CDK8s chart for Plane namespace, secret bridge, and ingress +135/-0

Add CDK8s chart for Plane namespace, secret bridge, and ingress

• Creates a dedicated "plane" CDK8s chart that provisions the namespace, a OnePasswordItem-backed Secret named plane-secrets, and a Tailscale ingress mapping Plane’s path-based services. Registers a backend probe for plane-web.

packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts

typed-helm-parameters.tsEnable typed values for the plane-enterprise Helm chart +2/-0

Enable typed values for the plane-enterprise Helm chart

• Imports PlaneenterpriseHelmValues and extends the HelmChartValuesMap with a "plane-enterprise" entry. Allows compile-time validation of the Argo Application valuesObject for Plane.

packages/homelab/src/cdk8s/src/misc/typed-helm-parameters.ts

plane.tsAdd Argo CD Applications for Plane vendor chart and infra chart +122/-0

Add Argo CD Applications for Plane vendor chart and infra chart

• Defines two Argo CD Applications: one deploying the upstream plane-enterprise chart from helm.plane.so with typed values, and one deploying a local "plane" infra chart from chartmuseum. Configures SeaweedFS S3 endpoint storage, disables PI/runner/vendor ingress, and sets CreateNamespace sync options.

packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts

setup-charts.tsInclude Plane infrastructure chart in CDK8s synthesis +2/-0

Include Plane infrastructure chart in CDK8s synthesis

• Adds createPlaneChart to the setup sequence so the infra resources are synthesized/published. Ensures probes and other late-stage wiring still run after chart creation.

packages/homelab/src/cdk8s/src/setup-charts.ts

versions.tsPin Plane enterprise chart and app versions +5/-0

Pin Plane enterprise chart and app versions

• Introduces pinned versions for the Plane enterprise Helm chart (3.1.0) and paired application version (v3.0.1). Annotates the Helm chart version for Renovate while keeping the app version manually paired.

packages/homelab/src/cdk8s/src/versions.ts

buckets.tfProvision SeaweedFS S3 bucket for Plane attachments +10/-0

Provision SeaweedFS S3 bucket for Plane attachments

• Adds an S3-compatible bucket named plane-attachments with prevent_destroy enabled. Documents that Plane uses an API storage proxy so clients do not require direct bucket access.

packages/homelab/src/tofu/seaweedfs/buckets.tf

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c15e64ab8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +14 to +18
Deploy the free Plane Commercial tier with the official `plane-enterprise`
Helm chart, pinned to chart `3.1.0` and app `v3.0.1`. Use Plane for private
issue tracking only; leave wiki/pages available but unused. Access is through
the Tailscale Kubernetes ingress at `plane.tailnet-1a49.ts.net`, with no public
Funnel exposure.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document Plane in the human architecture wiki

This introduces a persistent, operator-managed service with a new tailnet ingress and storage boundary, but records it only in an in-progress workflow plan; the inspected human-facing wiki has no Plane or corresponding homelab system-map entry. Add or update the nearest homelab wiki page so the deployed architecture and its private-access boundary remain discoverable alongside the code.

AGENTS.md reference: AGENTS.md:L68-L69

Useful? React with 👍 / 👎.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Plane PSA enforcement unspecified 🐞 Bug ☼ Reliability
Description
createPlaneChart() sets only PSA audit/warn labels on the plane Namespace but leaves enforce
behavior to the cluster default, while the Plane chart documentation explicitly calls out that
bundled local infra (postgres/redis/rabbitmq/etc.) is not covered by the PSA-restricted
securityContext. This makes the Plane rollout non-deterministic across clusters: if PSA restricted
is enforced by default, the bundled infra pods can be rejected and the deployment will not reach
healthy.
Code

packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[R27-29]

+        "pod-security.kubernetes.io/audit": "restricted",
+        "pod-security.kubernetes.io/warn": "restricted",
+      },
Evidence
The plane namespace is created with only audit/warn PSA labels; the Plane app configuration enables
bundled local services; and the generated chart docs explicitly state the securityContext is not
applied to bundled local infra workloads. Other namespaces that need to run non-restricted workloads
explicitly set an enforce label, showing the repo’s established pattern for deterministic PSA
behavior.

packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[20-31]
packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[24-36]
packages/homelab/src/cdk8s/generated/helm/plane-enterprise.types.ts[2988-3001]
packages/homelab/src/cdk8s/src/resources/argo-applications/ddns.ts[6-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `plane` namespace is labeled with PSA `audit`/`warn` only, which leaves `enforce` behavior to whatever the cluster default is. The Plane chart’s own documentation states that its hardened `securityContext` does **not** apply to bundled local infrastructure services (postgres/redis/rabbitmq/minio/opensearch), so a restricted-enforcing cluster can block those pods.

### Issue Context
This PR enables bundled local services (`local_setup: true`) for Plane’s postgres/redis/rabbitmq, so the namespace PSA enforcement choice directly affects whether Plane can run.

### Fix Focus Areas
- packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[20-31]
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[24-36]
- packages/homelab/src/cdk8s/generated/helm/plane-enterprise.types.ts[2988-3001]

### Requested change
Add an explicit `pod-security.kubernetes.io/enforce` label for the `plane` namespace that matches the intended policy (e.g. `privileged` if you want to allow the bundled infra pods to run) while keeping `audit`/`warn` as `restricted` for visibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. No Plane app sync ordering 🐞 Bug ☼ Reliability
Description
The PR introduces two independent Argo CD Applications (plane-infrastructure and plane) without any
sync-wave/dependency ordering, even though the vendor chart is configured to use a Secret name that
is materialized by the infrastructure app’s OnePasswordItem. This can produce an initially degraded
rollout (pods/jobs failing due to missing Secret data) until the infrastructure app and 1Password
operator reconcile.
Code

packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[R71-74]

+  return new Application(chart, "plane-app", {
+    metadata: {
+      name: PLANE_RELEASE,
+    },
Evidence
The vendor Plane Application references plane-secrets via external_secrets.*_existingSecret,
while the infra chart is responsible for creating the OnePasswordItem that produces the
plane-secrets Secret. Since both Applications are added without any ordering mechanism, Argo can
apply them in either order, creating a real (though often transient) dependency hazard.

packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[50-57]
packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[33-41]
packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[71-96]
packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[99-121]
packages/homelab/src/cdk8s/src/cdk8s-charts/apps.ts[132-136]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Two Argo CD Applications are added for Plane: one for infrastructure (namespace/ingress/1Password secret bridge) and one for the vendor Helm chart. There is no explicit ordering between them, but the vendor chart is configured to reference `plane-secrets`, which is produced asynchronously by the infra app via `OnePasswordItem`.

### Issue Context
Argo CD may reconcile Applications in any order; without ordering, the vendor workloads can start before `plane-secrets` exists, resulting in transient failures or degraded health until the infra app and the 1Password operator catch up.

### Fix Focus Areas
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[71-96]
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[99-121]
- packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[33-41]
- packages/homelab/src/cdk8s/src/cdk8s-charts/apps.ts[132-136]

### Requested change
Add `metadata.annotations["argocd.argoproj.io/sync-wave"]` to both Application CRs so `plane-infrastructure` syncs earlier than `plane` (e.g. infra = `-1`, vendor = `0`). This makes the rollout deterministic and reduces degraded/failed initial syncs due to missing secrets/ingress.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 66 rules

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +27 to +29
"pod-security.kubernetes.io/audit": "restricted",
"pod-security.kubernetes.io/warn": "restricted",
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Plane psa enforcement unspecified 🐞 Bug ☼ Reliability

createPlaneChart() sets only PSA audit/warn labels on the plane Namespace but leaves enforce
behavior to the cluster default, while the Plane chart documentation explicitly calls out that
bundled local infra (postgres/redis/rabbitmq/etc.) is not covered by the PSA-restricted
securityContext. This makes the Plane rollout non-deterministic across clusters: if PSA restricted
is enforced by default, the bundled infra pods can be rejected and the deployment will not reach
healthy.
Agent Prompt
### Issue description
The `plane` namespace is labeled with PSA `audit`/`warn` only, which leaves `enforce` behavior to whatever the cluster default is. The Plane chart’s own documentation states that its hardened `securityContext` does **not** apply to bundled local infrastructure services (postgres/redis/rabbitmq/minio/opensearch), so a restricted-enforcing cluster can block those pods.

### Issue Context
This PR enables bundled local services (`local_setup: true`) for Plane’s postgres/redis/rabbitmq, so the namespace PSA enforcement choice directly affects whether Plane can run.

### Fix Focus Areas
- packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[20-31]
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[24-36]
- packages/homelab/src/cdk8s/generated/helm/plane-enterprise.types.ts[2988-3001]

### Requested change
Add an explicit `pod-security.kubernetes.io/enforce` label for the `plane` namespace that matches the intended policy (e.g. `privileged` if you want to allow the bundled infra pods to run) while keeping `audit`/`warn` as `restricted` for visibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +71 to +74
return new Application(chart, "plane-app", {
metadata: {
name: PLANE_RELEASE,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. No plane app sync ordering 🐞 Bug ☼ Reliability

The PR introduces two independent Argo CD Applications (plane-infrastructure and plane) without any
sync-wave/dependency ordering, even though the vendor chart is configured to use a Secret name that
is materialized by the infrastructure app’s OnePasswordItem. This can produce an initially degraded
rollout (pods/jobs failing due to missing Secret data) until the infrastructure app and 1Password
operator reconcile.
Agent Prompt
### Issue description
Two Argo CD Applications are added for Plane: one for infrastructure (namespace/ingress/1Password secret bridge) and one for the vendor Helm chart. There is no explicit ordering between them, but the vendor chart is configured to reference `plane-secrets`, which is produced asynchronously by the infra app via `OnePasswordItem`.

### Issue Context
Argo CD may reconcile Applications in any order; without ordering, the vendor workloads can start before `plane-secrets` exists, resulting in transient failures or degraded health until the infra app and the 1Password operator catch up.

### Fix Focus Areas
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[71-96]
- packages/homelab/src/cdk8s/src/resources/argo-applications/plane.ts[99-121]
- packages/homelab/src/cdk8s/src/cdk8s-charts/plane.ts[33-41]
- packages/homelab/src/cdk8s/src/cdk8s-charts/apps.ts[132-136]

### Requested change
Add `metadata.annotations["argocd.argoproj.io/sync-wave"]` to both Application CRs so `plane-infrastructure` syncs earlier than `plane` (e.g. infra = `-1`, vendor = `0`). This makes the rollout deterministic and reduces degraded/failed initial syncs due to missing secrets/ingress.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant